﻿namespace MaciejGrabek.WebAPITools
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Net;
    using System.IO;
    using System.Threading.Tasks;
    using System.Net.Http.Headers;
    using System.Net.Http;

    public class ServiceCaller
    {
        public string ServiceUrl { get; private set; }

        public ServiceCaller(string serviceUrl)
        {
            ServiceUrl = serviceUrl.TrimEnd(new char[] { '/' });
        }

        /// <summary>
        /// Calls the services.
        /// </summary>
        /// <typeparam name="TResult">The type of the result.</typeparam>
        /// <typeparam name="TBody">The type of the body.</typeparam>
        /// <param name="callActionUrl">The call URL.</param>
        /// <param name="body">The body of request.</param>
        /// <param name="callMethod">The call method.</param>
        /// <param name="headers">The headers for request.</param>
        /// <returns>Result of call</returns>
        public async Task<TResult> CallService<TResult, TBody>(string callActionUrl, TBody body, CallMethod callMethod, Dictionary<string, string> headers)
        {
            HttpResponseMessage response = await GetResponse(callActionUrl, body, callMethod, headers);
            string content = await response.Content.ReadAsStringAsync();
            if (!String.IsNullOrWhiteSpace(content))
            {
                TResult result = JsonSerializationHelper.Deserialize<TResult>(content);
                return result;
            }
            else
            {
                return default(TResult);
            }
        }

        /// <summary>
        /// Calls the services and returns string response.
        /// </summary>
        /// <typeparam name="TBody">The type of the body.</typeparam>
        /// <param name="callActionUrl">The call URL.</param>
        /// <param name="body">The body of request.</param>
        /// <param name="callMethod">The call method.</param>
        /// <param name="headers">The headers for request.</param>
        /// <returns>Result of call</returns>
        public async Task<string> CallServicesForString<TBody>(string callActionUrl, TBody body, CallMethod callMethod, Dictionary<string, string> headers)
        {
            HttpResponseMessage response = await GetResponse(callActionUrl, body, callMethod, headers);
            string result = await response.Content.ReadAsStringAsync();
            return result;
        }

        private async Task<HttpResponseMessage> GetResponse<TBody>(string callActionUrl, TBody body, CallMethod callMethod, Dictionary<string, string> headers)
        {
            HttpClient client = new HttpClient();
            foreach (KeyValuePair<string, string> header in headers)
            {
                client.DefaultRequestHeaders.Add(header.Key, header.Value);
            }

            string url = string.Format("{0}/{1}", ServiceUrl, callActionUrl);
            HttpResponseMessage response = new HttpResponseMessage();

            switch (callMethod)
            {
                case CallMethod.Post:
                    StringContent postContent = new StringContent(JsonSerializationHelper.Serialize(body), Encoding.UTF8, "application/json");
                    response = await client.PostAsync(url, postContent);
                    break;
                case CallMethod.Get:
                    response = await client.GetAsync(url, HttpCompletionOption.ResponseContentRead);
                    break;
                case CallMethod.Delete:
                    response = await client.DeleteAsync(url);
                    break;
                case CallMethod.Put:
                    StringContent putContent = new StringContent(JsonSerializationHelper.Serialize(body), Encoding.UTF8, "application/json");
                    response = await client.PutAsync(url, putContent);
                    break;
                default:
                    response = null;
                    break;
            }


            return response;
        }
    }
}
